
from odoo import registry as registry_get
from odoo import api, SUPERUSER_ID

from functools import partial

from odoo.addons.base.models.res_users import name_boolean_group, name_selection_groups

import random
import json

from datetime import datetime
from dateutil.relativedelta import relativedelta

SUPER_COMPANY_ID = 1
DEMO_COMPANY_ID = 2


class Env2(object):
    def __init__(self, db):
        self.db = db

    def __getitem__(self, index):
        MyModel = index == 'res.users' and ResUsers or Model
        return MyModel(self.db, index, self)

    # def ref2(self, xmlid):
    #     res = self['ir.model.data'].xmlid_to_res_model_res_id(xmlid, True)
    #     return res

    def ref(self, xmlid):
        model, rid = self['ir.model.data'].xmlid_to_res_model_res_id(
            xmlid, True)

        obj = self[model]
        obj.id = rid
        obj.ids = [rid]

        return obj


class Model(object):
    def __init__(self, db, model, env):
        self.db = db
        self._name = model
        self.env = env
        self.id = None
        self.ids = []

    def __bool__(self):
        """ Test whether ``self`` is nonempty. """
        return bool(getattr(self, 'ids', True))

    __nonzero__ = __bool__

    def __getattr__(self, attr):
        rpc_methods = ['browse', 'search', 'create']

        if attr in rpc_methods:
            return partial(self.rpccall, attr)

        registry = registry_get(self.db)
        context = {}
        with registry.cursor() as cr:
            env = api.Environment(cr, SUPERUSER_ID, context)
            obj = env[self._name]
            fgs = obj.fields_get([], ['type', 'relation'])
            if attr not in fgs:
                return partial(self.odoocall, attr)

            obj = obj.browse(self.ids)

            field_value = getattr(obj, attr)
            if fgs[attr]['type'] not in ['many2one',  'one2many', 'many2many']:
                return field_value

            # relation 字段
            rel_obj = self.env[fgs[attr]['relation']]
            rel_obj.ids = field_value.ids
            rel_obj.id = field_value.id
            return rel_obj

    def rpccall(self, method, *args, **kwargs):
        registry = registry_get(self.db)
        context = {}
        with registry.cursor() as cr:
            env = api.Environment(cr, SUPERUSER_ID, context)
            obj = env[self._name]
            if self.ids:
                obj = obj.browse(self.ids)
            fn = getattr(obj, method)
            obj = fn(*args, **kwargs)
            self.id = obj.id
            self.ids = obj.ids
            return self

    def odoocall(self, method, *args, **kwargs):
        registry = registry_get(self.db)
        context = {}
        with registry.cursor() as cr:
            env = api.Environment(cr, SUPERUSER_ID, context)
            obj = env[self._name]
            if self.ids:
                obj = obj.browse(self.ids)
            fn = getattr(obj, method)
            return fn(*args, **kwargs)


class ResUsers(Model):
    def format_mail(self, code, sendtype):
        registry = registry_get(self.db)
        context = {}
        with registry.cursor() as cr:
            env = api.Environment(cr, SUPERUSER_ID, context)
            obj = env[self._name]
            # 在 user model 中定义一个 函数, 取邮件的格式
            print('send mail, user,', obj, hasattr(obj, 'format_mail'))

            if hasattr(obj, 'format_mail'):
                subject, content_text = obj.format_mail(code, sendtype)
                return subject, content_text

            if sendtype == 'auth':
                subject = '授权登录验证码'
                content_text = '授权登录验证码是: %s. 请返回授权登录页面输入你的验证码.' % code

            elif sendtype == 'register':
                subject = '注册验证码'
                content_text = '欢迎您注册, 验证码是: %s. 请返回注册页面输入你的验证码.' % code
            elif sendtype == 'reset_password':
                subject = '重置密码的验证码'
                content_text = '重置密码的验证码是: %s. 请返回重置密码页面输入你的验证码.' % code
            else:
                subject = '验证码'
                content_text = '验证码是: %s. 请返回页面输入你的验证码.' % code

            return subject, content_text

    def _random_code(self):
        return str(int((random.random() + 1) * 10000))[1:]

    def _code_clear(self, env, email):
        comment = env.user.comment
        info = comment and json.loads(comment) or {}
        del info[email]

        last2day = datetime.now() + relativedelta(days=-2)
        last2day = last2day.strftime('%Y-%m-%d')
        info = dict((k, v) for k, v in info.items() if v[1] >= last2day)
        env.user.comment = json.dumps(info)

    def code_clear(self, email):
        registry = registry_get(self.db)
        context = {}
        with registry.cursor() as cr:
            env = api.Environment(cr, SUPERUSER_ID, context)
            self._code_clear(env, email)

    def code_back(self, email):
        registry = registry_get(self.db)
        context = {}
        with registry.cursor() as cr:
            env = api.Environment(cr, SUPERUSER_ID, context)
            comment = env.user.comment
            info = comment and json.loads(comment) or {}
            code_today = info.get(email)
            return code_today and code_today[0]

    def code_send(self, email):
        registry = registry_get(self.db)
        context = {}
        with registry.cursor() as cr:
            env = api.Environment(cr, SUPERUSER_ID, context)
            comment = env.user.comment
            info = comment and json.loads(comment) or {}
            code = self._random_code()
            today = datetime.now().strftime('%Y-%m-%d')
            info[email] = (code, today)
            env.user.comment = json.dumps(info)
            return code

    def reset_password(self, db, field, value, password):
        registry = registry_get(self.db)
        context = {}
        with registry.cursor() as cr:
            env = api.Environment(cr, SUPERUSER_ID, context)

            obj = env[self._name]

            obj = obj.search([(field, '=', value)], limit=1)
            if not obj:
                return None
            ret = obj.write({'password': password})
            return ret

    def register(self, db, authtype, account, login, password):
        registry = registry_get(self.db)
        context = {}
        with registry.cursor() as cr:
            env = api.Environment(cr, SUPERUSER_ID, context)

            obj = env[self._name]

            if obj.search([('login', '=', login)], limit=1):
                return {'error': {'message': '%s is exist: %s' % ('login', login),
                                  'field': 'login', 'value': login}}
            if obj.search([(authtype, '=', account)], limit=1):
                return {'error': {'message': '%s is exist: %s' % (authtype, account),
                                  'field': authtype, 'value': account}}

            values = {
                'login': login, 'password': password,
                'name': login, authtype: account}

            if authtype == 'mobile':
                values['email'] = login

            user = obj.create(values)
            # print('create ok,1,', values)
            print('create ok,', user.id)

            gid_account = env.ref('account.group_account_user').id
            gid_erp_manager = env.ref('base.group_erp_manager').id
            gid_system = env.ref('base.group_system').id

            name_acc = name_boolean_group(gid_account)
            name_sys = name_selection_groups([gid_erp_manager, gid_system])

            values = {
                name_acc: True,
                name_sys: gid_erp_manager,
                'company_id': DEMO_COMPANY_ID,
                'company_ids': [(6, False, (SUPER_COMPANY_ID, DEMO_COMPANY_ID))]
            }
            # print('create ok,', gid_account, values)

            res = user.write(values)
            print('write ok,',  res)

            return {'result': {'uid': user.id}}
